23 #define foreach(x, v) for (typeof (v).begin() x=(v).begin(); x !=(v).end(); ++x)
24 #define For(i, a, b) for (int i=(a); i<(b); ++i)
25 #define D(x) cout << #x " is " << x << endl
28 #define dprintf DEBUG and printf
29 #define dcout DEBUG and cout
31 inline int cmp(double x
, double y
= 0, double tol
= 1e-9) {
32 return (x
<= y
+ tol
) ? (x
+ tol
< y
) ? -1 : 0 : 1;
40 Vector(double X
, double Y
) : x(X
), y(Y
) {}
41 inline void normalize() {
42 double length
= sqrt(x
* x
+ y
* y
);
43 x
/= length
; y
/= length
;
45 bool operator < (const Vector
&o
) const {
46 if (cmp(x
, o
.x
) != 0) return cmp(x
, o
.x
) < 0;
47 return cmp(y
, o
.y
) < 0;
49 bool operator == (const Vector
&o
) const {
50 return (cmp(x
, o
.x
) == 0 and
61 Person(double X
, double Y
, const Vector
&D
, string Name
) : x(X
), y(Y
), d(D
.x
, D
.y
), name(Name
) {}
63 bool operator < (const Person
&o
) { return name
< o
.name
; }
65 double timeToFall() const;
67 friend ostream
&operator<<(ostream
&stream
, const Person
&p
);
70 double Person::timeToFall() const {
71 double horizontal
= cmp(this->d
.x
, 0) < 0 ? this->x
/ (-this->d
.x
) : (Width
- this->x
) / (this->d
.x
);
72 double vertical
= cmp(this->d
.y
, 0) < 0 ? this->y
/ (-this->d
.y
) : (Height
- this->y
) / (this->d
.y
);
73 return min(horizontal
, vertical
);
76 ostream
&operator<<(ostream
&stream
, const Person
&p
) {
77 stream
<< p
.name
<< " is at (" << p
.x
<< ", " << p
.y
<< ") moving in direction <" << p
.d
.x
<< ", " << p
.d
.y
<< "> (Might fall in " << p
.timeToFall() << " seconds)";
82 int type
; // 0 = free fall, 1 = collision
84 Vector point
; // point of collision, if any
85 vector
<int> people
; // the guy who fell or the two fellows that collided (contains indexes)
88 bool operator < (const Event
&o
) const {
89 if (cmp(time
, o
.time
) != 0) return cmp(time
, o
.time
) < 0;
90 if (type
!= o
.type
) return type
< o
.type
;
91 if (type
== 0) return name
< o
.name
;
92 return point
< o
.point
;
96 double dot(const Vector
&a
, const Vector
&b
) {
97 return a
.x
* b
.x
+ a
.y
* b
.y
;
100 bool outsideWorld(double x
, double y
) {
101 if (cmp(x
, 0) < 0) return true;
102 if (cmp(x
, Width
) > 0) return true;
103 if (cmp(y
, 0) < 0) return true;
104 if (cmp(y
, Height
) > 0) return true;
108 // Returns the time where person A and B would collide, or -1 if they won't.
109 double timeOfCollision(const Person
&a
, const Person
&b
, Vector
&pointOfCollision
) {
110 if (cmp(a
.x
, b
.x
) == 0 and cmp(a
.y
, b
.y
) == 0) return -1; // They are on the same point, won't collide.
112 double x0
= a
.x
, x1
= a
.x
+ a
.d
.x
;
113 double y0
= a
.y
, y1
= a
.y
+ a
.d
.y
;
115 double x2
= b
.x
, x3
= b
.x
+ b
.d
.x
;
116 double y2
= b
.y
, y3
= b
.y
+ b
.d
.y
;
118 double t0
= (y3
-y2
)*(x0
-x2
)-(x3
-x2
)*(y0
-y2
);
119 double t1
= (x1
-x0
)*(y2
-y0
)-(y1
-y0
)*(x2
-x0
);
120 double det
= (y1
-y0
)*(x3
-x2
)-(y3
-y2
)*(x1
-x0
);
122 if (cmp(det
, 0) == 0){
124 if (cmp(t0
, 0) == 0 || cmp(t1
, 0) == 0) {
125 // they lie on same line. But they might not collide (if they travel in the same direction)
126 if (cmp(dot(a
.d
, b
.d
), 1) == 0) { // They travel in the same direction
129 pointOfCollision
.x
= x0
+ (x2
- x0
) / 2;
130 pointOfCollision
.y
= y0
+ (y2
- y0
) / 2;
131 double dist
= hypot(x2
- x0
, y2
- y0
) / 2;
132 if (cmp(x0
+ dist
* a
.d
.x
, pointOfCollision
.x
) != 0 or cmp(y0
+ dist
* a
.d
.y
, pointOfCollision
.y
) != 0 or
133 cmp(x2
+ dist
* b
.d
.x
, pointOfCollision
.x
) != 0 or cmp(y2
+ dist
* b
.d
.y
, pointOfCollision
.y
) != 0) {
134 // they travel in opposite directions, but after traveling half the distance they haven't collided, so they'll never collide
137 return dist
; // they'll collide in half their distance because they travel in opposite directions
139 //just parallel, no intersection
146 if (cmp(t0
, t1
) == 0 and cmp(0.0, t0
) <= 0 and cmp(0.0, t1
) <= 0){
147 double x
= x0
+ t0
*(x1
-x0
);
148 double y
= y0
+ t0
*(y1
-y0
);
149 if (outsideWorld(x
, y
)) return -1;
150 pointOfCollision
.x
= x
;
151 pointOfCollision
.y
= y
;
158 int Cases
; cin
>> Cases
;
160 dprintf("Begin case:\n");
162 cin
>> Width
>> Height
;
164 vector
<Person
> people
;
165 for (int i
= 0; i
< n
; ++i
) {
167 cin
>> p
.x
>> p
.y
>> p
.d
.x
>> p
.d
.y
>> p
.name
;
168 p
.d
.x
-= p
.x
; p
.d
.y
-= p
.y
; p
.d
.normalize();
173 double timeOfLastDeath
= -1;
174 string lastToDie
= "";
175 while (people
.size() > 0) {
176 vector
< Event
> events
;
178 for (int i
= 0; i
< people
.size(); ++i
) {
181 fall
.time
= people
[i
].timeToFall();
182 fall
.people
.push_back(i
);
183 fall
.name
= people
[i
].name
;
184 events
.push_back(fall
);
187 for (int j
= i
+ 1; j
< people
.size(); ++j
) {
188 Person a
= people
[i
], b
= people
[j
];
190 double t
= timeOfCollision(a
, b
, point
);
193 //printf("%s and %s won't collide\n", a.name.c_str(), b.name.c_str());
198 collision
.point
= point
;
199 collision
.people
.push_back(i
); collision
.people
.push_back(j
);
200 events
.push_back(collision
);
201 dprintf("%s and %s could collide at <%lf, %lf> in %lf seconds\n", a
.name
.c_str(), b
.name
.c_str(), point
.x
, point
.y
, t
);
206 assert(events
.size() > 0);
207 sort(events
.begin(), events
.end());
209 if (events
[0].type
== 0) { // free fall, just remove this guy and try again
210 if (cmp(events
[0].time
, timeOfLastDeath
) > 0 or cmp(events
[0].time
, timeOfLastDeath
) == 0 and people
[events
[0].people
[0]].name
> lastToDie
) {
211 lastToDie
= people
[events
[0].people
[0]].name
;
212 timeOfLastDeath
= events
[0].time
;
214 people
.erase(people
.begin() + events
[0].people
[0]);
215 dprintf("%s just fell of at time %lf.\n", lastToDie
.c_str(), events
[0].time
);
216 dprintf("Remaining people are:\n");
217 for (int i
= 0; i
< people
.size(); ++i
){
218 dcout
<< " " << people
[i
] << endl
;
222 double timeOfCollision
= events
[0].time
;
223 Vector pointOfCollision
= events
[0].point
;
224 set
< int > peopleWhoCollided
;
225 for (int i
= 0; i
< events
.size() and cmp(events
[i
].time
, timeOfCollision
) == 0 and events
[i
].point
== pointOfCollision
; i
++) {
226 peopleWhoCollided
.insert(events
[i
].people
.begin(), events
[i
].people
.end());
228 dprintf("%d people just collided! Holy bananas!\n", (int)peopleWhoCollided
.size());
229 if (peopleWhoCollided
.size() == 2) { // nothing serious, just swap their directions and try again
230 int a
= *peopleWhoCollided
.begin(), b
= *(--peopleWhoCollided
.end());
231 double dist
= hypot(pointOfCollision
.x
- people
[a
].x
, pointOfCollision
.y
- people
[a
].y
);
232 assert(cmp(dist
, hypot(pointOfCollision
.x
- people
[b
].x
, pointOfCollision
.y
- people
[b
].y
)) == 0);
233 for (int i
= 0; i
< people
.size(); ++i
){
234 people
[i
].x
+= dist
* people
[i
].d
.x
;
235 people
[i
].y
+= dist
* people
[i
].d
.y
;
237 swap(people
[a
].d
, people
[b
].d
);
238 dprintf("Swapped direction between %s and %s\n", people
[a
].name
.c_str(), people
[b
].name
.c_str());
239 dprintf("Remaining people are:\n");
240 for (int i
= 0; i
< people
.size(); ++i
){
241 dcout
<< " " << people
[i
] << endl
;
245 // delete those guys who collided
246 vector
< Person
> newPeople
;
247 for (int i
= 0; i
< people
.size(); ++i
) {
248 if (peopleWhoCollided
.count(i
) > 0) {
249 if (cmp(events
[0].time
, timeOfLastDeath
) > 0 or cmp(events
[0].time
, timeOfLastDeath
) == 0 and people
[i
].name
> lastToDie
) {
250 lastToDie
= people
[i
].name
;
251 timeOfLastDeath
= events
[0].time
;
253 dprintf(" %s died in the collision.\n", people
[i
].name
.c_str());
255 newPeople
.push_back(people
[i
]);
259 dprintf("Remaining people are:\n");
260 for (int i
= 0; i
< people
.size(); ++i
){
261 dcout
<< " " << people
[i
] << endl
;
272 assert(lastToDie
.size() > 0);
273 cout
<< lastToDie
<< endl
;